#include"freeip.hpp"
#include"http.hpp"

Ipnet::Ipnet(const string& s)
{
  istringstream iss(s);
  set_addr(iss);
  set_mask(iss);
}

Ipnet::Ipnet(istream&is)
{
  set_addr(is); set_mask(is);
}

void Ipnet::set_addr(istream&is)
{
  char dot;
  is>>addr[0]>>dot>>addr[1]>>dot>>addr[2]>>dot>>addr[3];
}

void Ipnet::set_mask(istream&is)
{
  char dot;
  is>>mask[0]>>dot>>mask[1]>>dot>>mask[2]>>dot>>mask[3];    
}
  
int Ipnet::ip_diff(const int*aip) const
{
  int r;
  for (int i=0; i<4; ++i) {
    r = (aip[i] & mask[i]) - addr[i];
    if (r) break;
  }
  return r;
}

string Ipnet::get_addr() const
{
  ostringstream ss;
  ss<<addr[0]<<'.'<<addr[1]<<'.'<<addr[2]<<'.'<<addr[3];
  return ss.str();
}
  
string Ipnet::get_mask() const
{
  ostringstream ss;
  ss<<mask[0]<<'.'<<mask[1]<<'.'<<mask[2]<<'.'<<mask[3];
  return ss.str();
}
  
bool Ipnet::operator <(const struct Ipnet &r) const
{
  int o;
  for (int i=0; i<4; ++i) {
    o = addr[i] - r.addr[i];
    if (o) return o<0;
  }

  for (int i=0; i<4; ++i) {
    o = mask[i] - r.mask[i];
    if (o) return o>0;
  }
  return false;
}

vector<Ipnet> freeipnets;

bool is_freeip(const int* aip)
{
  int h=freeipnets.size(), l=0;
  if (h==0) return true;//TODO: true or false
  int m, r;
  while (l<h) {
    m = (h+l)/2;
    r = freeipnets[m].ip_diff(aip);
    if (r==0) return true;
    if (r>0) l = m + 1;
    else h = m;
  }
  return false;
}

bool is_freeip(const string& ip) {
  int aip[4];  char dot;
  istringstream ips(ip);
  ips>>aip[0]>>dot>>aip[1]>>dot>>aip[2]>>dot>>aip[3]>>aip[4];
  return is_freeip(aip);
}

bool is_freeip(const struct sockaddr *addr, int af) {
  if (af==AF_INET6) return false;//TODO:how to do this?
#ifdef WIN32
  const char *p=inet_ntoa(((const struct sockaddr_in*)addr)->sin_addr);
#else
  char nbuf[128];
  const char *p=inet_ntop(AF_INET, &(((const struct sockaddr_in*)addr)->sin_addr),
                          nbuf, sizeof(nbuf));
#endif
  if (p==NULL) return false;
  return is_freeip(string(p));
}

bool is_freeip(const TcpHost& h) {
  bool r;
  struct addrinfo *rp;
  for (rp=h.ai; rp!=0; rp=rp->ai_next) {
    r = is_freeip(rp->ai_addr, rp->ai_family);
    if (r) return true;
  }
  return false;
}

void gen_pac(ostream &os, const string&proxy)
{
  Url up(proxy);
  os<<"// generated by fcproxy(pointer@tom.com)\n"
    "function FindProxyForURL(url, host) {\n"
    "var cnips=[";
  int h=freeipnets.size();
  for (int i=0; i<h; ++i) {
    if (i>0) os<<",\n";
    os<<"[\""
      <<freeipnets[i].get_addr()
      <<"\",\""
      <<freeipnets[i].get_mask()
      <<"\"]";
  }
  os<<"];\n\n";
  os<<"if (isPlainHostName(host) || dnsDomainIs(host,\".cn\"))  return \"DIRECT\";\n"
  "if(isInNet(host,\"127.0.0.0\",\"255.0.0.0\"))  return \"DIRECT\";\n"
  "if(isInNet(host,\"10.0.0.0\",\"255.0.0.0\"))  return \"DIRECT\";\n"
  "if(isInNet(host,\"172.16.0.0\",\"255.240.0.0\"))  return \"DIRECT\";\n"
  "if(isInNet(host,\"192.168.0.0\",\"255.255.0.0\"))  return \"DIRECT\";\n"
  "if (isResolvable(host)) {\n"
  "for (var i=0; i<cnips.length; ++i) {\n"
  "if (isInNet(host, cnips[i][0], cnips[i][1]))\n"
  "return \"DIRECT\";\n"
  "}\n"
  "if(shExpMatch(host, \"*.cn\"))\n"
  "return \"DIRECT\";\n"
  "return \"PROXY "<<up.host<<":"<<up.port<<"; DIRECT\";\n"
  "}\n"
  "return \"DIRECT\";\n"
  "}"<<endl;
}
